import React from 'react'
import {Form, Col, Input} from 'antd'
import PropTypes from "prop-types";
import ComboBox from "../ComboBox";
import {getCompByType} from "./helper/getCompByType";
import {getDerivedStateFromPropsFunc} from "./helper/lifeCycle";
import {forEach, forIn, indexOf, isArray, isBoolean, isEmpty, isNumber} from "lodash-es";
import {QueryFilter, isNotEmpty} from "jh-utils";
import BaseField from "./BaseField";
import {getFilterByCode as getFByCode, filterCodes as fCodes, getFilterPreview} from './helper/filterPreview';

/** 在这里将 filterCodes 和 getFilterByCode 导出，是为了兼容旧代码 **/
export const filterCodes = fCodes;
export const getFilterByCode = getFByCode;

/**
 * 过滤条件组件的基类
 */
export default class BaseFilter extends BaseField {

    static propTypes = {
        ...BaseField.propTypes,
        compLabel: PropTypes.string,
        componentType: PropTypes.string,
        fieldName: PropTypes.string,
        onRef: PropTypes.func,
        /**
         * 当数据有变化时的回调
         * @param value string comboBox 组件的值
         */
        onChange: PropTypes.func,
        /**
         * 是否隐藏下拉框
         */
        comboBoxHidden: PropTypes.bool,
        /**
         * “值-组件”的额外属性。
         * 比如：如果“值-组件”是 FinderSelect, 则 valueCompProps 即支持 FinderSelect 组件的所有属性
         */
        valueCompProps: PropTypes.object,
        /**
         * 是否需要“介于”条件。默认 false
         *  true：会加上“介于”条件，值会变成数组类型。
         */
        needBetween: PropTypes.bool,
        /**
         * 默认的过滤类型。不设置，默认是 filterCodes.eq.code
         */
        defaultFilterCode: PropTypes.any
    };

    static defaultProps = {
        defaultFilterCode: filterCodes.eq.code
    };

    static getDerivedStateFromProps(nextProps, preState) {
        let reObj = BaseField.getDerivedStateFromProps(nextProps, preState);
        return getDerivedStateFromPropsFunc(nextProps, preState, (changedValue) => {
            // @param changedValue 即 nextProps 中有变化的 value 或 defaultValue 的值。
            // 在这个方法里返回需要更新到 state 里的值。
            // （注：defaultValue 的处理已经在 getDerivedStateFromPropsFunc 中默认处理，所以这里不用返回了）
            const {comboVal, compVal} = changedValue || {};
            return {
                ...(reObj || {}),
                comboVal: comboVal || nextProps.defaultFilterCode,
                compVal: isBoolean(compVal) ? compVal : (compVal || undefined)
            };
        });
    }

    /**
     * 字段类型。'filter': 作为过滤条件使用
     * @type {string}
     */
    static fieldType = 'filter';

    /**
     * 条件枚举下拉列表数据
     * @type {[{
        code: string,
        code: string,
        name: string,
        preview: string
    }]}
     */
    comboData = [];

    initState(props) {
        const {comboVal, compVal} = props.value || props.defaultValue || {};
        return {
            ...super.initState(props),
            comboVal: comboVal || props.defaultFilterCode,
            compVal: compVal || undefined,
        }
    }

    getValue() {
        return this.getAjaxData()
    }

    /**
     * 【可被继承后，子类进行重写】
     * 提供给外部直接调用，获取本组件的数据
     * @param newValues object 组件新的值，如果有传入，则可通过这个值来改变 getAjaxData 的返回值
     * @return object { comboVal: '枚举选择框的值', compVal: '筛选条件组件的值', filterVal: '用于查询', previewValue: '用于回显' }
     */
    getAjaxData(newValues = {}) {
        const reObj = {
            comboVal: this.state.comboVal,
            compVal: this.state.compVal,

            componentType: this.props.componentType,
            fieldName: this.props.fieldName,
            label: this.props.compLabel,
            format: this.props.format,
            floatNum: this.props.floatNum,
            selector: this.props.selector,
            ...newValues
        };

        // 将值处理成可用于 jh-utils/formatFilter 方法的格式： string | any[] | { expression: '', value: '' }
        // 存放在 filterVal 字段
        reObj.filterVal = this.dealValue4Filter(reObj);
        // console.log('BaseFilter getAjaxData', reObj)

        /**
         * 用于回显筛选条件的值
         * {fieldNames: '字段名', label: '字段中文描述', text: '回显文本'}
         */
        // let previewValue = getFilterPreview(reObj, {
        //     formatMsgByCn: this.formatMsgByCn.bind(this)
        // });
        //
        // if (previewValue) {
        //     reObj.previewValue = previewValue;
        // }

        return reObj;
    }

    /**
     * 将值处理成可用于 jh-utils/formatFilter 方法的格式：
     * string | any[] | { expression: '', value: '' }
     * @param comboVal
     * @param compVal
     * @return {string | any[] | { expression: string, value: * }}
     */
    dealValue4Filter({comboVal, compVal}) {
        const reVal = {expression: !isEmpty(comboVal) ? comboVal : QueryFilter.EQUAL, value: compVal};

        switch (comboVal) {
            case filterCodes.eq.code:
                // 如果值是数组，说明有多个值，则用 IN。否则是 =
                if (isArray(compVal)) {
                    reVal.value = compVal.join(',');

                    if (compVal.length > 0) {
                        reVal.expression = QueryFilter.IN;
                        break;
                    }
                }
                reVal.expression = QueryFilter.EQUAL;
                break;
            case filterCodes.noEq.code:
                // 如果值是数组，说明有多个值，则用 NOT IN。否则是 <>
                if (isArray(compVal)) {
                    reVal.value = compVal.join(',');

                    if (compVal.length > 0) {
                        reVal.expression = QueryFilter.NOT_IN;// 'NOT IN';
                        break;
                    }
                }
                reVal.expression = QueryFilter.NOT_EQUAL;
                break;
            case filterCodes.fuzzy.code:
                reVal.expression = QueryFilter.LIKE; // 'LIKE';
                break;
            // case filterCodes.gt.code:
            //     reVal.expression = '>';
            //     break;
            // case filterCodes.gtEq.code:
            //     reVal.expression = '>=';
            //     break;
            // case filterCodes.lt.code:
            //     reVal.expression = '<';
            //     break;
            // case filterCodes.ltEq.code:
            //     reVal.expression = '<=';
            //     break;
            // case filterCodes.between.code:
            //     reVal.expression = 'BETWEEN';
            //     break;
            // case filterCodes.null.code:
            //     reVal.expression = 'IS NULL';
            //     break;
            // case filterCodes.noNull.code:
            //     reVal.expression = 'IS NOT NULL';
            //     break;
        }
        return reVal;
    }

    /**
     * 【可被继承后，子类进行重写】
     * 处理筛选组件的值。
     * 例如 InputComp 组件，在默认的 onChange 回调中返回的参数是 event 对象，而不是输入框的值，
     * 这时就需要重写这个方法，从 event 中获取到输入框的值，然后返回输入框的值。示例代码如下：
     * dealCompValue(value) {
     *      if(value.target) return value.target.value;
     *      else return value;
     *  }
     * @param value
     * @return {*}
     */
    dealCompValue(value) {
        return value;
    }

    getCompProps(moreProps = {}) {
        return moreProps
    }

    /**
     * 筛选组件的数据有变化时的回调
     */
    hdlValueChange(value) {
        const compVal = this.dealCompValue(value);
        // 作为受控组件
        if ('value' in this.props) {
            this.runPropsFunc('onChange')(this.getAjaxData({compVal}));

        } else {

            this.setState({compVal}, () => {
                this.runPropsFunc('onChange')(this.getAjaxData());
            });
        }

    }

    /**
     * 枚举选择框的数据有变化时的回调
     * @param value
     */
    hdlComboChange(value) {

        let compVal = this.state.compVal;

        if (filterCodes.between.code === value) {

            if (!isArray(compVal) && !isEmpty(compVal)) {
                compVal = [compVal];
            } else {
                compVal = undefined;
            }
        } else {

            if (isArray(compVal)) {
                compVal = compVal[0];
            }
        }

        // 作为受控组件
        if ('value' in this.props) {
            this.props.onChange && this.props.onChange(this.getAjaxData({comboVal: value, compVal}));

        } else {
            this.setState({comboVal: value, compVal}, () => {
                this.props.onChange && this.props.onChange(this.getAjaxData());
            });
        }
    }

    /**
     * 判断是否可显示筛选组件
     * @return {boolean}
     */
    canShowComp() {
        let value = this.state.comboVal;
        return filterCodes.null.code !== value && filterCodes.noNull.code !== value;
    }

    /**
     * 【可被继承后，子类进行重写】
     * 筛选条件的组件
     * @return ReactNode
     */
    compRender(moreProps = {}) {
        return getCompByType(this.props.componentType, this.getCompProps(moreProps));
    }

    mainRender(context) {
        const {
            selector, finderCode, dataType, format, floatNum, appins, customprops = {},
            appCode, comboBoxHidden = false, valueCompProps, plural, referenceAppInfo
        } = this.getProps();
        const canShowComp = this.canShowComp();
        const tmpO = {
            dataType, appins, customprops,
            value: this.state.compVal,
            format, floatNum,
            onChange: this.hdlValueChange.bind(this),
            style: {width: comboBoxHidden ? '100%':'calc(100% - 100px)'}
        };
        if (selector) tmpO.selector = selector;
        if (finderCode) tmpO.finderCode = finderCode;
        if (appCode) tmpO.appCode = appCode;

        if (plural) { // 查找器多态
            tmpO.plural = plural;
            tmpO.referenceAppInfo = referenceAppInfo;
        }

        if (!isEmpty(valueCompProps)) {
            forIn(valueCompProps, (v, k) => {
                tmpO[k] = v;
            })
        }

        const moreCompProps = this.getCompProps(tmpO);

        return (
            <Input.Group compact>
                {!comboBoxHidden && <ComboBox
                    needPH={false}
                    value={this.state.comboVal}
                    compData={this.comboData}
                    onChange={this.hdlComboChange.bind(this)}
                    style={{minWidth: 100, width: 100}}
                />}
                {
                    canShowComp && (this.compRender(moreCompProps))
                }
            </Input.Group>
        )
    }
}